package com.efast.cafe.portal.security.core.impl;

import com.efast.cafe.commponent.log.ext.CafeLogger;
import com.efast.cafe.commponent.log.ext.CafeLoggerFactory;
import com.efast.cafe.framework.bean.ResultBean;
import com.efast.cafe.framework.constant.CommonConstant;
import com.efast.cafe.framework.constant.SecurityConstant;
import com.efast.cafe.framework.exception.ServiceException;
import com.efast.cafe.portal.bean.base.BaseCompanyInfoBean;
import com.efast.cafe.portal.bean.common.ParameterResultBean;
import com.efast.cafe.portal.bean.common.PortalUserDetails;
import com.efast.cafe.portal.bean.common.PortalUserSecurityBean;
import com.efast.cafe.portal.entity.company.PortalCompanyRole;
import com.efast.cafe.portal.security.core.AuthenticationFactory;
import com.efast.cafe.portal.security.core.AuthenticationTypeService;
import com.efast.cafe.portal.service.base.IBaseCompanyInfoService;
import com.efast.cafe.portal.service.common.IParameterService;
import com.efast.cafe.portal.service.common.IResourceService;
import com.efast.cafe.portal.service.company.IPortalCompanyUserService;
import com.efast.cafe.util.ConfigUtil;
import com.efast.cafe.util.IpAddressUtil;
import com.efast.cafe.util.StringUtil;
import net.sf.json.JSONObject;
import org.slf4j.MDC;
import org.slf4j.event.Level;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.ldap.core.LdapTemplate;
import org.springframework.ldap.core.support.DefaultIncrementalAttributesMapper;
import org.springframework.ldap.query.LdapQueryBuilder;
import org.springframework.security.authentication.AuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.UUID;

@Component
public class LdapAuthenticationProcessor implements AuthenticationTypeService {

    private CafeLogger logger = CafeLoggerFactory.getLogger(LdapAuthenticationProcessor.class);
    @Autowired
    private LdapTemplate ldapTemplate;
    @Autowired
    private IPortalCompanyUserService portalCompanyUserService;

    @Autowired
    private IResourceService portalResourceService;

    @Autowired
    private IParameterService parameterService;

    @Autowired
    private IBaseCompanyInfoService baseCompanyInfoService;

    @Override
    public UsernamePasswordAuthenticationToken authentication(HttpServletRequest request) {
        String LDAP_BASE = ConfigUtil.getValue("LDAP_BASE");
        String LDAP_ATTR_KEY = ConfigUtil.getValue("LDAP_ATTR_KEY");
        String companyCode = request.getParameter(AuthenticationFactory.SPRING_SECURITY_FORM_COMPANYCODE_KEY);
        String username = request.getParameter(AuthenticationFactory.SPRING_SECURITY_FORM_UNAME_KEY);
        List<DefaultIncrementalAttributesMapper> search = null;
        try {
            ldapTemplate.setIgnorePartialResultException(true);
            search = ldapTemplate.search(LdapQueryBuilder
                            .query()
                            .base(LDAP_BASE)
                            .where(LDAP_ATTR_KEY).is(username),
                    new DefaultIncrementalAttributesMapper(LDAP_ATTR_KEY));
        } catch (Exception e) {
            logger.error("", e);
            throw new AuthenticationServiceException(SecurityConstant.ERROR_CODE.LDAP_CONNECT_FAIL);
        }
        if (search == null || search.size() == 0) {
            throw new AuthenticationServiceException(SecurityConstant.ERROR_CODE.LDAP_USER_NOT_FOUND);
        }

        String pwd = UUID.randomUUID().toString();
        return new UsernamePasswordAuthenticationToken(
                companyCode + CommonConstant.J_COMPANY_USERNAME_SEPARATOR + username + CommonConstant.J_COMPANY_USERNAME_SEPARATOR + pwd, pwd);
    }

    @Override
    public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        PortalUserDetails userDetail = (PortalUserDetails) authentication.getPrincipal();
        PortalUserSecurityBean user = userDetail.getUser();
        MDC.put(CommonConstant.USERNAME_FIELD, user.getUname());
        MDC.put(CommonConstant.COMPANYCODE_FIELD, user.getCompany_code());
        MDC.put("clientIP", IpAddressUtil.getIpAdrress(request));
        HttpSession session = request.getSession();
        List<String> roleNames = new ArrayList<>();
        List<PortalCompanyRole> roles = portalCompanyUserService.queryUserHasRoleList(user.getUname(), user.getCompany_code());
        roles.forEach(r -> {
            roleNames.add(r.getRoleName());
        });
        user.setRoleNames(roleNames);
        session.setAttribute(CommonConstant.PORTAL_USER_OBJECT, user);
        session.setAttribute(CommonConstant.CURRENT_LOGIN_USER_NAME_KEY, user.getUname());
        session.setAttribute(CommonConstant.CURRENT_LOGIN_USER_COMPANYCODE_KEY, user.getCompany_code());
        HashSet<String> checkauthSet = portalResourceService.queryPurviewPathByCompanyUserAndRoleDB(user.getCompany_code(), user.getUname());
        HashSet<String> allPurvewPathSet = portalResourceService.queryAllPurviewPathDB();
        session.setAttribute(CommonConstant.CURRENT_LOGIN_USER_PURVIEWSET_SESSIONKEY, checkauthSet);
        session.setAttribute(CommonConstant.CURRENT_LOGIN_USER_ALLPURVIEWSET_SESSIONKEY, allPurvewPathSet);
        session.setAttribute("request_locale", "zh_CN");
        JSONObject res = new JSONObject();
        JSONObject jo = new JSONObject();
        jo.put("companyCode", user.getCompany_code());
        jo.put("username", user.getUname());
        jo.put("email", StringUtil.isNotBlank(user.getEmail()) ? user.getEmail() : "");
        jo.put("phone", StringUtil.isNotBlank(user.getPhone()) ? user.getPhone() : "");
        jo.put("type", StringUtil.isNotBlank(user.getType()) ? user.getType() : "");
        jo.put("isManager", user.getDefault_user() != null ? user.getDefault_user() : 0);
        jo.put("userLevel", StringUtil.isNotBlank(user.getUser_level()) ? user.getUser_level() : "");
        jo.put("sex", user.getSex() != null ? user.getSex() : null);
        jo.put("realName", StringUtil.isNotBlank(user.getReal_name()) ? user.getReal_name() : user.getUname());
        jo.put("roleList", roleNames);
        res.put("success", true);
        List<ParameterResultBean> params = parameterService.getParameters(CommonConstant.ParameterGroups.WEB_INDEX, user.getCompany_code(), user.getUname());
        BaseCompanyInfoBean companyInfo = baseCompanyInfoService.queryByCode(user.getCompany_code());
        jo.put("companyName", companyInfo.getCompany_name());
        jo.put("generateFormId", companyInfo.getGenerateFormId());
        jo.put("params", params);
        res.put("object", jo);
        res.put("errorCode", "");
        res.put("errorMessage", "");
        String token = UUID.randomUUID().toString();
        res.put("token", token);
        session.setAttribute("token", token);

        logger.cacheLog(Level.INFO, jo.toString(), "登录系统");

        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().print(res.toString());
    }

    @Override
    public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {

        JSONObject jo = new JSONObject();
        jo.put("success", false);

        String errorCode = "2002";

        Throwable throwable = exception.getCause();


        if (throwable != null && throwable instanceof ServiceException) {
            ServiceException bad = (ServiceException) throwable;
            errorCode = bad.getCode();
        } else if (exception instanceof AuthenticationServiceException) {
            AuthenticationServiceException ex = (AuthenticationServiceException) exception;
            errorCode = ex.getMessage();
            if (errorCode.equals("-1")) {
                jo.put("message", "Authentication method not supported: " + request.getMethod());
            }
        }
        //2002 密码错误
        jo.put("errorCode", errorCode);

        //response
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().print(jo.toString());
    }

    @Override
    public void onLogoutSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
        ResultBean res = new ResultBean(true, "");
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        response.getWriter().print(JSONObject.fromObject(res).toString());
    }
}
